package com.example.framework;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
import java.io.InputStream;
import java.lang.reflect.Array;

public class ReflectionFramework {
    private Properties properties;

    public ReflectionFramework() {
        properties = new Properties();
        try (InputStream input = getClass().getClassLoader().getResourceAsStream("config.properties")) {
            if (input == null) {
                throw new RuntimeException("Unable to find config.properties");
            }
            properties.load(input);
        } catch (Exception e) {
            throw new RuntimeException("Error loading configuration: " + e.getMessage(), e);
        }
    }

    public Object createObject(String key) throws Exception {
        String className = properties.getProperty(key);
        if (className == null) {
            throw new IllegalArgumentException("No class defined for key: " + key);
        }


        String constructorKey = key + ".constructor";
        String constructorParams = properties.getProperty(constructorKey);

        Class<?> clazz = Class.forName(className);

        if (constructorParams == null || constructorParams.trim().isEmpty()) {

            return clazz.getDeclaredConstructor().newInstance();
        } else {

            String[] parts = constructorParams.split("\\|");
            if (parts.length < 2) {
                throw new IllegalArgumentException("Invalid constructor configuration for: " + key);
            }

            String[] paramTypes = parts[0].split(",");
            String[] paramValues = parts[1].split(",");

            Class<?>[] parameterTypes = new Class<?>[paramTypes.length];
            Object[] arguments = new Object[paramValues.length];

            for (int i = 0; i < paramTypes.length; i++) {
                parameterTypes[i] = parseType(paramTypes[i].trim());
                arguments[i] = parseValue(paramValues[i].trim(), parameterTypes[i]);
            }

            Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
            return constructor.newInstance(arguments);
        }
    }

    public Object invokeMethod(Object obj, String methodKey) throws Exception {
        String methodInfo = properties.getProperty(methodKey);
        if (methodInfo == null) {
            throw new IllegalArgumentException("No method defined for key: " + methodKey);
        }


        String[] parts = methodInfo.split("\\|");
        String methodName = parts[0];


        if (parts.length == 1) {
            Method method = obj.getClass().getMethod(methodName);
            return method.invoke(obj);
        }


        if (parts.length < 3) {
            throw new IllegalArgumentException("Invalid method configuration for: " + methodKey);
        }

        String[] paramTypes = parts[1].split(",");
        String[] paramValues = parts[2].split(",");

        if (paramTypes.length != paramValues.length) {
            throw new IllegalArgumentException("Parameter types and values count mismatch for: " + methodKey);
        }

        Class<?>[] parameterTypes = new Class<?>[paramTypes.length];
        Object[] arguments = new Object[paramValues.length];

        for (int i = 0; i < paramTypes.length; i++) {
            parameterTypes[i] = parseType(paramTypes[i].trim());
            arguments[i] = parseValue(paramValues[i].trim(), parameterTypes[i]);
        }

        Method method = obj.getClass().getMethod(methodName, parameterTypes);
        return method.invoke(obj, arguments);
    }

    public Object invokeStaticMethod(String methodKey) throws Exception {
        String methodInfo = properties.getProperty(methodKey);
        if (methodInfo == null) {
            throw new IllegalArgumentException("No static method defined for key: " + methodKey);
        }

        String[] parts = methodInfo.split("\\|");
        String fullMethodName = parts[0];


        int lastDotIndex = fullMethodName.lastIndexOf('.');
        if (lastDotIndex == -1) {
            throw new IllegalArgumentException("Invalid static method format: " + fullMethodName);
        }

        String className = fullMethodName.substring(0, lastDotIndex);
        String methodName = fullMethodName.substring(lastDotIndex + 1);

        Class<?> clazz = Class.forName(className);


        if (parts.length == 1) {
            Method method = clazz.getMethod(methodName);
            return method.invoke(null);
        }


        if (parts.length < 3) {
            throw new IllegalArgumentException("Invalid static method configuration for: " + methodKey);
        }

        String[] paramTypes = parts[1].split(",");
        String[] paramValues = parts[2].split(",");

        if (paramTypes.length != paramValues.length) {
            throw new IllegalArgumentException("Parameter types and values count mismatch for: " + methodKey);
        }

        Class<?>[] parameterTypes = new Class<?>[paramTypes.length];
        Object[] arguments = new Object[paramValues.length];

        for (int i = 0; i < paramTypes.length; i++) {
            parameterTypes[i] = parseType(paramTypes[i].trim());
            arguments[i] = parseValue(paramValues[i].trim(), parameterTypes[i]);
        }

        Method method = clazz.getMethod(methodName, parameterTypes);
        return method.invoke(null, arguments);
    }

    private Class<?> parseType(String typeName) throws ClassNotFoundException {
        switch (typeName) {
            case "int": return int.class;
            case "Integer": return Integer.class;
            case "double": return double.class;
            case "Double": return Double.class;
            case "boolean": return boolean.class;
            case "Boolean": return Boolean.class;
            case "float": return float.class;
            case "Float": return Float.class;
            case "long": return long.class;
            case "Long": return Long.class;
            case "short": return short.class;
            case "Short": return Short.class;
            case "byte": return byte.class;
            case "Byte": return Byte.class;
            case "char": return char.class;
            case "Character": return Character.class;
            case "String": return String.class;
            default:
                // 处理数组类型
                if (typeName.endsWith("[]")) {
                    String elementTypeName = typeName.substring(0, typeName.length() - 2);
                    Class<?> elementType = parseType(elementTypeName);
                    return Array.newInstance(elementType, 0).getClass();
                }
                return Class.forName(typeName);
        }
    }

    private Object parseValue(String value, Class<?> type) {
        if (type == String.class) {
            return value;
        } else if (type == int.class || type == Integer.class) {
            return Integer.parseInt(value);
        } else if (type == double.class || type == Double.class) {
            return Double.parseDouble(value);
        } else if (type == boolean.class || type == Boolean.class) {
            return Boolean.parseBoolean(value);
        } else if (type == float.class || type == Float.class) {
            return Float.parseFloat(value);
        } else if (type == long.class || type == Long.class) {
            return Long.parseLong(value);
        } else if (type == short.class || type == Short.class) {
            return Short.parseShort(value);
        } else if (type == byte.class || type == Byte.class) {
            return Byte.parseByte(value);
        } else if (type == char.class || type == Character.class) {
            return value.charAt(0);
        } else if (type.isArray()) {
            // 简单处理数组，这里只支持String数组
            if (type.getComponentType() == String.class) {
                return value.split(",");
            }
            throw new IllegalArgumentException("Unsupported array type: " + type.getComponentType());
        } else {
            throw new IllegalArgumentException("Unsupported parameter type: " + type.getName());
        }
    }
}